﻿// vtest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "..\..\dvb\dvb.h"
#include "..\..\auth\ucode\ucode.h"
#include "..\..\auth\ucode\urank.h"
#include "..\pciead\pciead.h"
#include "..\pciead\vcard_def.h"
#include "..\pciead\firm_def.h"
#include "..\..\auth\vac_reg.h"
#include "..\..\auth\app_reg.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <conio.h>

// 2021-01-13: 配合长期有效ucode，取消注册时授权操作码是否合格，只是记录在卡以便跟踪
// 2019-10-14: 取消威程固态盘文件读写
// 2018-11-12: endData==0表示永久注册，与licCode一致
// 2017-12-20: 测试固态文件上传/下载字符串ups/downs
// 2017-08-07: 支持App注册，将原来写制造商和机器名的地方改为AppName和AppRegCode(字符串形式)
// 2017-06-26: 支持威程板
// 2017-04-01: validThr更名endDate
// 2017-03-29: 检查注册有效期，输出validThr
// 2016-11-29: 匹配pciead v1.80
// 2015-7-1: 服务级别注册时检查user，非0必须该user对应配套厂家处理。

#define PROGRAMER_CODE	30865601

static int  PciCardInfo2Id(int einfo[])
{
	static int seeds[10] = {
		12345, 50214, 48902, 74329, 18427,
		75209, 38923, 19328, 97548, 74824 };
	int sum = 0;
	for (int i = 0; i < 6; i++) {
		sum += (einfo[i] & 0x7fff);
	}
	int seed = seeds[sum % 10];
	return(((seed * sum + einfo[1]) & 0x7fffffff) % 1000000);
}

static void PrintUsage(void)
{
	char info[81];
	sprintf_s(info, 81, "Usage: vtest [0/1/2/3] <cmd> <parameters...> [operator_code]\n");
	std::cout << info;
	sprintf_s(info, 81, "<cmd>: wsn wtype, wuser, wvbgn, wvend, wkey, rparam, wparam\n");
	std::cout << info;
	sprintf_s(info, 81, "       westr, wenum, output, od\n");
	std::cout << info;
}

// 仅仅计数威程卡
int vcount_main(void)
{
	DWORD dllVer = PcieadGetDllVer();;
	char dllVerStr[10];
	Dvb2String(dllVerStr, dllVer);

	int n = PcieadCountDevices();
	printf("PCIEAD v%s counts %d devices.\n", dllVerStr, n);
	return(n);
}

// 用于pciead测试
//int vtest_main(int argc, char* argv[])
int main(int argc, char* argv[])
{
	WORD models[10], vers[10];
	char info[81];

	int n = PcieadScanAndOpen(models, vers);

	BOOL cmdOk = TRUE;
	if (argc == 1) {					// 扫描并列印基本信息
		DWORD dllVer = PcieadGetDllVer();;
		char dllVerStr[10];
		Dvb2String(dllVerStr, dllVer);

		sprintf_s(info, 81, "PCIEAD v%s has opened %d devices.\n", dllVerStr, n);
		std::cout << info;

		int einfo[6];
		for (int i = 0; i < n; i++) {
			int sn = VcardGetSn(i);

			einfo[0] = VcardReadEeprom(i, EE_SN_HIGH);
			einfo[1] = VcardReadEeprom(i, EE_SN_LOW);
			int type = einfo[2] = VcardReadEeprom(i, EE_TYPE);
			int user = einfo[3] = VcardReadEeprom(i, EE_USER);
			int vbegin = einfo[4] = VcardReadEeprom(i, EE_VBGN);
			int vend = einfo[5] = VcardReadEeprom(i, EE_VEND);
			int mid = PciCardInfo2Id(einfo);	// 兼容PCI卡的机器号

			int klow = VcardReadEeprom(i, EE_KLOW);
			int khigh = VcardReadEeprom(i, EE_KHIGH);
			int regCode = klow + khigh * 10000;
			int licCode = GetLicenseCode(mid, regCode);
			int endDate = (licCode <= 0) ? licCode : LicCode2EndDate(vbegin, licCode);
			
			const char* modelClass;
			if ((models[i] & 0xFF00) == 0x1900) {
				modelClass = "D900";
			}
			else if ((models[i] & 0xFFF0) == 0x1880) {
				modelClass = "V880";
			}
			else if ((models[i] & 0xFFF0) == 0x1890) {
				modelClass = "V890";
			}
			else {
				modelClass = "V800";
			}
			sprintf_s(info, 81, "%s[%d]: model=0x%x ver=0x%x sn=%d \n", modelClass, i, models[i], vers[i], sn);
			std::cout << info;
			sprintf_s(info, 81, "    type=%d user=%d [%d-%d] mid=%d regCode=%d endDate=%d\n", type, user, vbegin, vend, mid, regCode, endDate);

			std::cout << info;
			char eString[21];
			int eNumber[4];
			memset(eString, 0x00, sizeof(eString));
			memset(eNumber, 0x00, sizeof(eNumber));
			VcardReadEString(i, eString, 0);
			eNumber[0] = VcardReadENumber(i, 0);
			eNumber[1] = VcardReadENumber(i, 1);
			eNumber[2] = VcardReadENumber(i, 2);
			eNumber[3] = VcardReadENumber(i, 3);
			sprintf_s(info, 81, "    eString=\"%s\" eNumbers=[%08X,%08X,%08X,%08X]\n", eString, eNumber[0], eNumber[1], eNumber[2], eNumber[3]);
			std::cout << info;
		}
	}
	else {
		int cardIndex;					// 单卡位置可以缺省，多卡需要argv[1]指定卡槽位置0/1/2/3
		const char* szCmd;
		int param1, param2;
		double fparam1, fparam2;
		char* strParam1;
		if ((strlen(argv[1]) == 1) && isdigit(argv[1][0])) {// argv[1]是单字母数字为指定卡槽位置
			cardIndex = atoi(argv[1]);
			szCmd = (argc >= 3) ? argv[2] : "acq";
			strParam1 = argv[3];
			param1 = (argc >= 4) ? strtol(argv[3], NULL, 0) : 0;
			fparam1 = (argc >= 4) ? atof(argv[3]) : 0.0;
			param2 = (argc >= 5) ? strtol(argv[4], NULL, 0) : 0;
			fparam2 = (argc >= 5) ? atof(argv[4]) : 0.0;
		}
		else {
			cardIndex = 0;									// 缺省是第一个卡槽位置
			szCmd = argv[1];
			strParam1 = argv[2];
			param1 = (argc >= 3) ? strtol(argv[2], NULL, 0) : 0;
			fparam1 = (argc >= 3) ? atof(argv[2]) : 0;
			param2 = (argc >= 4) ? strtol(argv[3], NULL, 0) : 0;
			fparam2 = (argc >= 4) ? atof(argv[3]) : 0.0;
		}

		if (!_strcmpi(szCmd, "wsn")) {
			long newSn = param1;
			long operKey = param2;
			UcodeOpen(PROGRAMER_CODE, newSn);
			WORD empNo = DecodeEmpNo(newSn, operKey);
			if (UcodeGetRank(empNo, newSn) >= RANK_PROD) {
				VcardLog(cardIndex, empNo);
				VcardWriteEeprom(cardIndex, EE_SN_HIGH, (newSn / 10000));
				VcardWriteEeprom(cardIndex, EE_SN_LOW, (newSn % 10000));

				char operName[21];
				UcodeGetEnName(operName, empNo);
				sprintf_s(info, 81, "Thank %s for writing SN.\n", operName);
				std::cout << info;
			}
			else {
				sprintf_s(info, 81, "No authority of modification!\n");
				std::cout << info;
			}
			UcodeClose();
		}
		else if (!_strcmpi(szCmd, "wtype") || !_strcmpi(szCmd, "wuser") || !_strcmpi(szCmd, "wvbgn") || !_strcmpi(szCmd, "wvend") || !_strcmpi(szCmd, "wkey")) {
			int sn = VcardGetSn(cardIndex);
			long wtarget = param1;
			long operKey = param2;
			UcodeOpen(PROGRAMER_CODE, sn);
			WORD empNo = DecodeEmpNo(wtarget, operKey);
			int urank = UcodeGetRank(empNo, sn);
			char operName[21];
			strcpy_s(operName, 21, "Someone");
			UcodeGetEnName(operName, empNo);
			if (urank >= RANK_REPAIR) {						// 这个级别必须是朗杰公司的员工
				VcardLog(cardIndex, empNo);
				if (!_strcmpi(szCmd, "wtype")) {
					VcardWriteEeprom(cardIndex, EE_TYPE, wtarget);
					sprintf_s(info, 81, "%s has modified type.\n", operName);
					std::cout << info;
				}
				else if (!_strcmpi(szCmd, "wuser")) {
					VcardWriteEeprom(cardIndex, EE_USER, wtarget);
					sprintf_s(info, 81, "%s has modified user.\n", operName);
					std::cout << info;
				}
				else if (!_strcmpi(szCmd, "wvbgn")) {
					VcardWriteEeprom(cardIndex, EE_VBGN, wtarget);
					sprintf_s(info, 81, "%s has modified begin of validity.\n", operName);
					std::cout << info;
				}
				else if (!_strcmpi(szCmd, "wvend")) {
					VcardWriteEeprom(cardIndex, EE_VEND, wtarget);
					sprintf_s(info, 81, "%s has modified end of validity.\n", operName);
					std::cout << info;
				}
				else if (!_strcmpi(szCmd, "wkey")) {
					VcardWriteEeprom(cardIndex, EE_KLOW, (wtarget % 10000));
					VcardWriteEeprom(cardIndex, EE_KHIGH, (wtarget / 10000));
					sprintf_s(info, 81, "%s has modified regCode.\n", operName);
					std::cout << info;
				}
			}
			else {
				// 注册操作权限管理全部转向网上，本工具无条件写入注册码
				if (urank == RANK_MAINT) {
					VcardLog(cardIndex, empNo);				// 能查表的记下操作者id
				}
				else {
					VcardLog(cardIndex, operKey % 10000);	// 查不了的记下操作码后4位，可以在注册历史查
				}
				if (!_strcmpi(szCmd, "wkey")) {
					VcardWriteEeprom(cardIndex, EE_KLOW, (wtarget % 10000));
					VcardWriteEeprom(cardIndex, EE_KHIGH, (wtarget / 10000));
					sprintf_s(info, 81, "%s has registered successfully.\n", operName);
					std::cout << info;
				}
			}
			UcodeClose();
		}
		else if (!_strcmpi(szCmd, "rparam")) {// 用户参数0->7对应AD_MODE->EMP_NO，转换成pciad顺序的eeprom地址
			if (param1 <= 7) {
				int eeAddr = (7 - param1) * 2;
				WORD eeData = VcardReadEeprom(cardIndex, eeAddr);
				sprintf_s(info, 81, "Read Eeprom[%d]=%d\n", eeAddr, eeData);
				std::cout << info;
			}
			else {
				sprintf_s(info, 81, "Read Eeprom beyond!\n");
				std::cout << info;
			}
		}
		else if (!_strcmpi(szCmd, "wparam")) {
			if (param1 <= 7) {
				int eeAddr = (7 - param1) * 2;
				WORD eeData = param2;
				VcardWriteEeprom(cardIndex, eeAddr, eeData);
				sprintf_s(info, 81, "Write Eeprom[%d]=%d\n", eeAddr, eeData);
				std::cout << info;
			}
			else {
				sprintf_s(info, 81, "Write Eeprom beyond!\n");
				std::cout << info;
			}
		}
		else if (!_strcmpi(szCmd, "westr")) {
			VcardWriteEString(cardIndex, 0, strParam1);
			sprintf_s(info, 81, "Write eString(\"%s\")\n", strParam1);
			std::cout << info;
		}
		else if (!_strcmpi(szCmd, "wenum")) {
			VcardWriteENumber(cardIndex, param1, param2);
			sprintf_s(info, 81, "Write eNumber[%ld]=%ld\n", param1, param2);
			std::cout << info;
		}
		else if (!_strcmpi(szCmd, "output")) {
			int chnl = param1;
			int bin = param2;
			WORD chnlTypes[16];
			int n = VcardGetCtrlChnl(cardIndex, chnlTypes);
			if (chnl >= 0 && chnl < n) {
				VcardOutput(cardIndex, chnl, bin, 0);
				switch (chnlTypes[chnl]) {
				case CTRL_CHNL_PWM:
					sprintf_s(info, 81, "Output pulse_width(%d)\n", bin);
					std::cout << info;
					break;
				case CTRL_CHNL_PNM:
					sprintf_s(info, 81, "Output pules_number(%d)\n", bin);
					std::cout << info;
					break;
				case CTRL_CHNL_DA:
					sprintf_s(info, 81, "Output DA(%d)\n", bin);
					std::cout << info;
					break;
				default:
					break;
				}
			}
			else {
				sprintf_s(info, 81, "Beyond channel range[0-%d]\n", n - 1);
				std::cout << info;
			}
		}
		else if (!_strcmpi(szCmd, "od")) {
			WORD mask = (WORD)param1;
			VcardOutputDigital(cardIndex, mask);
			sprintf_s(info, 81, "Output digital level(0x%04x)\n", mask);
			std::cout << info;
		}
		else {
			cmdOk = FALSE;
		}
	}


	if (!cmdOk) {
		PrintUsage();
	}

	PcieadClose();
	return 0;
}
